<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2023/2/13
 * Time: 10:31
 */

namespace app\logic\index\pay;

use app\common\lib\Common;
use app\common\lib\RedisQueue;
use app\common\lib\Wechat;
use app\exception\IndexException;
use app\logic\BaseLogic;
use app\model\pay\WechatPayNotifyLogModel;
use app\model\pay\WechatPayOrderModel;
use app\model\product\InternalProductModel;
use app\model\product\VipProductModel;
use app\model\user\UserIncomeFlowModel;
use app\model\user\UserInviteRelationModel;
use app\model\user\UserModel;
use app\model\user\UserPointFlowModel;
use app\model\user\UserRechargeOrderIncomeModel;
use app\model\user\UserRechargeOrderModel;
use support\Db;

class WeixinPayLogic extends BaseLogic
{
    protected static $instance;

    public function __construct()
    {
        parent::__construct();
    }

    public static function getInstance()
    {
//        if(is_object(self::$instance)){
//            return self::$instance;
//        }

        return  new self();
    }

    public function wechatPay($param)
    {
        $param['type'] = $param['type']??1;
        if($param['type']==1){
            $where = ['product_id'=>$param['product_id'],'platform'=>'weixin','status'=>1,'isdel'=>0];
            $product = VipProductModel::getInstance()->getWhere($where)->first();
            $product && $description = '开通会员: 包'.$product['unit'];
            $sourceTable = VipProductModel::getInstance()->getTable();
        }else{
            $where = ['product_id'=>$param['product_id'],'platform'=>'weixin','status'=>1,'isdel'=>0];
            $product = InternalProductModel::getInstance()->getWhere($where)->first();
            $product && $description = '充值点数:'.$product['point_nums'];
            $sourceTable = InternalProductModel::getInstance()->getTable();
        }

        if($product==false){
            throw new IndexException(4020,'产品已下架');
        }

        $outTradeNo = (string)(round(microtime(true)*1000).Common::randString(4,1));

        $payParam = [
            'out_trade_no'=>$outTradeNo,
            'amount'=>$product['sale_price'],
            'description'=>$description??'购买虚拟产品',
        ];

        //微信支付下单获取 prepay_id
        $result = Wechat::getInstance()->appPay($payParam);
        if(!empty($result['prepay_id'])){
            //创建订单
            $insert = [
                'user_sn'=>request()->curUserId,
                'out_trade_no'=>$outTradeNo,
                'description'=>$payParam['description'],
                'amount'=>$product['sale_price'],
                'prepay_id'=>$result['prepay_id'],
                'sourceid'=>$product['product_id'],
                'source_table'=>$sourceTable,
                'order_status'=>0,
                'point_nums'=>$product['point_nums']??0,
                'days'=>$product['days']??0,
                'product_type'=>$param['type'],
            ];
            WechatPayOrderModel::getInstance()->insertGetId($insert);

            //发起支付，返回支付参数
            $result = Wechat::getInstance()->getAppPaySignAndParam($result['prepay_id']);

            return $result;
        }

        throw new IndexException(2008,'订单创建错误');
    }

    public function wechatPayNotify()
    {
        $inBodyResourceArray = Wechat::getInstance()->wechatPayNotify();

        $insert = [
            'notify_headers'=>json_encode(request()->header(),256),
            'notify_content'=>request()->rawBody(),
            'decrypt_content'=>$inBodyResourceArray ? json_encode($inBodyResourceArray,256) : '',
            'out_trade_no'=>$inBodyResourceArray['out_trade_no']??'',
            'transaction_id'=>$inBodyResourceArray['transaction_id']??'',
        ];

        WechatPayNotifyLogModel::getInstance()->insertGetId($insert);

        try{
            Db::connection('mysql')->beginTransaction();
            if(!empty($inBodyResourceArray['out_trade_no'])){
                $find = WechatPayOrderModel::getInstance()->where(['out_trade_no' => $inBodyResourceArray['out_trade_no']])->first();
                if($find && $find['order_status']==0){
                    $update = [
                        'out_trade_no'=>$inBodyResourceArray['out_trade_no'],
                        'transaction_id'=>$inBodyResourceArray['transaction_id'],
                        'order_status'=>$inBodyResourceArray['trade_state']=='SUCCESS'?1:2,
                        'pay_time'=>date('Y-m-d H:i:s',strtotime($inBodyResourceArray['success_time'])),
                    ];

                    //todo 1 更新微信支付订单信息
                    WechatPayOrderModel::getInstance()->getWhere(['id'=>$find['id']])->update($update);

                    $find = WechatPayOrderModel::getInstance()->where(['out_trade_no' => $inBodyResourceArray['out_trade_no']])->first();

                    //todo 2 添加到充值订单表
                    if($inBodyResourceArray['trade_state']=='SUCCESS'){
                        $maxId =  UserRechargeOrderModel::getInstance()->getWhere([['order_no','>',0]])->max('order_no');
                        $orderOn = Common::getSnCode($maxId,'60', 6, 2);
                        $orderData = [
                            'user_sn'                  => $find['user_sn'],
                            'order_no'                 => $orderOn,
                            'product_type'             => $find['product_type'],
                            'trade_no'                 => $inBodyResourceArray['out_trade_no'],
                            'original_trade_no'        => $inBodyResourceArray['out_trade_no'],
                            'order_status'             => 6,
                            'pay_status'               => 1,
                            'pay_time'                 => date('Y-m-d H:i:s',strtotime($inBodyResourceArray['success_time'])),
                            'money'                    => $find['amount'],
                            'payment'                  => 3,

                            'isrenew'                  => 0,
                            'product_id'               => $find['sourceid'],
                            // 'expires_date'             => $find['product_type']==1?round(strtotime(date('Y-m-d'))+round($find['days']*86400)):0,
                            'expires_date'             => $find['product_type']==1?round(strtotime($inBodyResourceArray['success_time'])+round($find['days']*86400)):0,
                            'update_pay_status_source' => 2,
                            'notification_type'        => '',
                            'subtype'                  => '',
                            'notify_time'              => time(),
                            'point_nums'              => $find['point_nums'],
                        ];

                        $orderData['id'] = UserRechargeOrderModel::getInstance()->insertGetId($orderData);

                        //todo 3 给用户增加点数和分成计算
                        $this->dealPayOrderAfterSaveData($find['user_sn'],$orderData);

                        //加入巨量引擎支付回传队列
                        //生成唯一的请求id
                        $requestId = Common::getRequestId();
                        // 队列名
                        $queue = 'oceanengineAttribution';
                        // 数据，可以直接传数组，无需序列化
                        $data = ['requestid' => $requestId, 'user_sn'=>$find['user_sn'],'type'=>'pay' ,'amount'=>$find['amount']];
                        // 投递消息
                        RedisQueue::getInstance()->sendQueue($queue, $data);
                    }
                }
            }

            Db::connection('mysql')->commit();

            $result = [
                'code'=>$inBodyResourceArray ? 'SUCCESS' :  'FAIL',
                'message'=>$inBodyResourceArray ? '成功' :  '失败',
            ];
            return $result;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            $result = [
                'code'=>'FAIL',
                'message'=>'失败',
            ];
            return $result;
        }
    }

    protected function dealPayOrderAfterSaveData($userSn,$order)
    {
        try{
            Db::connection('mysql')->beginTransaction();
            //todo 2 更新vip用户有效期
            if($order['product_type']==1){
                UserModel::getInstance()->getWhere(['user_sn'=>$userSn])->update(
                    [
                        'vip_expire_time'=>date('Y-m-d H:i:s',$order['expires_date']),
                        'is_vip'=>1,
                    ]
                );
            }

            //todo 3 今天没送点数，现在立即就送点数
            if($order['product_type']==1){
                $where = [
                    'user_sn'=>$userSn,
                    'type'=>1,
                    'way'=>1,
                    ['created_at','>=',date('Y-m-d 00:00:00')]
                ];
                $pointNums = (int) UserPointFlowModel::getInstance()->getWhere($where)->sum('nums');
                if($pointNums<$order['point_nums']){
                    $insert = [
                        'user_sn'=>$userSn,
                        'nums'=>round($order['point_nums']-$pointNums),
                        'type'=>1,
                        'way'=>1,
                        'sourceid'=>$order['id'],
                        'source_table'=>UserRechargeOrderModel::getInstance()->getTable(),
                    ];
                    UserPointFlowModel::getInstance()->insertGetId($insert);
                }
            }else{
                $insert = [
                    'user_sn'=>$userSn,
                    'nums'=>round($order['point_nums']),
                    'type'=>2,
                    'way'=>1,
                    'sourceid'=>$order['id'],
                    'source_table'=>UserRechargeOrderModel::getInstance()->getTable(),
                ];
                $folwid = UserPointFlowModel::getInstance()->insertGetId($insert);
            }

            //todo 4 给邀请用户分成
            $parentUserSn = UserInviteRelationModel::getInstance()->getWhere(['invite_user_sn'=>$userSn,'level'=>1])->value('user_sn');
            $parentUser = UserModel::getInstance()->getWhere(['user_sn'=>$parentUserSn])->first();
            //是否已经分过
            $where = [
                'user_sn'=>$parentUserSn,
                'income_source_user_sn'=>$userSn,
                'order_no'=>$order['order_no'],
            ];
            $count = UserRechargeOrderIncomeModel::getInstance()->getWhere($where)->count();

            if($parentUser && $count==false){

                $levelData = config('param.vip_level'.$parentUser['agent_level']);
                $incomeRate = ($levelData['income_rate']??10);

                $insert = [
                    'user_sn'=>$parentUserSn,
                    'order_no'=>$order['order_no'],
                    'level_type'=>1,
                    'income_source_user_sn'=>$userSn,
                    'income_amount'=>round($order['money']*$incomeRate/100,2),
                    'pay_amount'=>$order['money'],
                    'pay_time'=>$order['pay_time'],
                    'agent_level'=>$parentUser['agent_level'],
                    'reward_rate'=>$incomeRate,
                    'product_type'=>$order['product_type'],
                ];
                $incomeId = UserRechargeOrderIncomeModel::getInstance()->insertGetId($insert);
                $insertFlow = [
                    'user_sn'=>$parentUserSn,
                    'amount'=>$insert['income_amount'],
                    'type'=>1,
                    'source_table'=>UserRechargeOrderIncomeModel::getInstance()->getTable(),
                    'sourceid'=>$incomeId,
                    'income_source_user_sn'=>$userSn,
                    'income_date'=>$order['pay_time'],
                ];
                UserIncomeFlowModel::getInstance()->insertGetId($insertFlow);
            }
            Db::connection('mysql')->commit();
        }catch (\Exception $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        return true;
    }

    public function wechatRefundNotify()
    {
        $inBodyResourceArray = Wechat::getInstance()->wechatPayNotify();

        //return file_put_contents(storage_path('wechatRefundNotify.log'),"\n".json_encode($inBodyResourceArray),8);

        try{
            Db::connection('mysql')->beginTransaction();
//            if(!empty($inBodyResourceArray['out_refund_no'])){
//                $find = RefundApplyModel::getInstance()->where(['out_refund_no' => $inBodyResourceArray['out_refund_no']])->first();
//                if($find['status']==1){
//                    $update = [
//                        'pay_order_sn'=>$inBodyResourceArray['out_trade_no'],
//                        'wechat_pay_order_sn'=>$inBodyResourceArray['transaction_id'],
//                        'status'=>2,
//                        'refund_type'=>1,
//                        'refund_time'=>date('Y-m-d H:i:s',strtotime($inBodyResourceArray['success_time'])),
//                        'updatetime'=>date('Y-m-d H:i:s',strtotime($inBodyResourceArray['success_time'])),
//                    ];
//
//                    //todo 1 更新申请退款信息
//                    RefundApplyModel::getInstance()->getWhere(['out_refund_no' => $inBodyResourceArray['out_refund_no']])->update($update);
//
//                    $find = RefundApplyModel::getInstance()->getWhere(['out_refund_no' => $inBodyResourceArray['out_refund_no']])->first();
//
//                    //todo 2 更新订单状态
//                    if($find){
//                        $update = [
//                            'refund_time'=>date('Y-m-d H:i:s',strtotime($inBodyResourceArray['success_time'])),
//                            'order_status'=>5,
//                            'updatetime'=>date('Y-m-d H:i:s'),
//                        ];
//                        OrderModel::getInstance()->getWhere(['ordersn'=>$find['ordersn'],'order_status'=>6])->update($update);
//
//                        //todo 3 删除分成数据
//                        SettlementIncomeModel::getInstance()->getWhere(['ordersn'=>$find['ordersn'],'user_flow_id'=>0])->update(['isdel'=>1,'updatetime'=>date('Y-m-d H:i:s')]);
//                    }
//                }
//            }

            $insert = [
                'notify_content'=>request()->getContent(),
                'decrypt_content'=>json_encode($inBodyResourceArray,256),
                'out_refund_no'=>$inBodyResourceArray['out_refund_no']??'',
                'pay_order_sn'=>$inBodyResourceArray['out_trade_no']??'',
                'wechat_pay_order_sn'=>$inBodyResourceArray['transaction_id']??'',
                'createtime'=>date('Y-m-d H:i:s'),
                'type'=>2,
            ];
//            WechatPayNotifyLog::getInstance()->insertGetId($insert);

            file_put_contents(runtime_path('wiexin_refund_notify.log'),json_encode($insert,256)."\n\n",8);
            Db::connection('mysql')->commit();

            $result = [
                'code'=>$inBodyResourceArray ? 'SUCCESS' :  'FAIL',
                'message'=>$inBodyResourceArray ? '成功' :  '失败',
            ];
            return $result;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            $result = [
                'code'=>'FAIL',
                'message'=>'失败',
            ];
            return $result;
        }
    }

}